from redis_connection import redis_conn as redis
import requests
import config
import pendulum
import logging
import time


def refresh_enterprise_app_token() -> bool:
    _logger = logging.getLogger("REF_ENT_TOKEN")
    refresh_result = False
    need_refresh = not redis.exists(config.ENT_ACCESS_TOKEN)
    if not need_refresh:
        expires = pendulum.parse(redis.hget(config.ENT_ACCESS_TOKEN, "expires").decode())
        need_refresh = (expires - pendulum.now()).total_seconds() < 360
    if need_refresh:
        try:
            token_request = requests.get("https://qyapi.weixin.qq.com/cgi-bin/gettoken",
                                         params={
                                             "corpid": config.ENT_CORP_ID,
                                             "corpsecret": config.ENT_APP_SECRET})
            token_result = token_request.json()
            if "errcode" in token_result and token_result["errcode"] == 0:
                expires = pendulum.now().add(seconds=token_result["expires_in"])
                pipe = redis.pipeline()
                pipe.hset(config.ENT_ACCESS_TOKEN, "token", token_result["access_token"])
                pipe.hset(config.ENT_ACCESS_TOKEN, "expires", expires.to_atom_string())
                pipe.execute()
                _logger.info("刷新企业应用Token成功。")
                refresh_result = True
            else:
                _logger.error(f"刷新企业应用Token出现错误，"
                              f"错误码{token_result['errcode']}：{token_result['errmsg']}。")
        except requests.ConnectionError:
            _logger.error(f"刷新企业应用Token时无法建立与微信服务器的连接。")
        except ValueError:
            _logger.error(f"企业应用Access Token请求解析失败。")
    else:
        refresh_result = True
    return refresh_result


def refresh_enterprise_app_js_api_ticket() -> bool:
    _logger = logging.getLogger("REF_ENT_JS_TICKET")
    refresh_result = False
    need_refresh = not redis.exists(config.ENT_JS_API_TOKEN)
    if not need_refresh:
        expires = pendulum.parse(redis.hget(config.ENT_JS_API_TOKEN, "expires").decode())
        need_refresh = (expires - pendulum.now()).total_seconds() < 360
    if need_refresh:
        try:
            token_request = requests.get("https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket",
                                         params={"access_token": redis.hget(config.ENT_ACCESS_TOKEN, "token")})
            token_result = token_request.json()
            if "errcode" in token_result and token_result["errcode"] == 0:
                expires = pendulum.now().add(seconds=token_result["expires_in"])
                pipe = redis.pipeline()
                pipe.hset(config.ENT_JS_API_TOKEN, "token", token_result["ticket"])
                pipe.hset(config.ENT_JS_API_TOKEN, "expires", expires.to_atom_string())
                pipe.execute()
                _logger.info("刷新企业应用JSAPI TICKET成功。")
                refresh_result = True
            else:
                _logger.error(f"刷新企业应用JSAPI TICKET出现错误，"
                              f"错误码{token_result['errcode']}：{token_result['errmsg']}。")
        except requests.ConnectionError:
            _logger.error(f"刷新企业应用JSAPI TICKET时无法建立与微信服务器的连接。")
        except ValueError:
            _logger.error(f"刷新企业应用JSAPI TICKET时Access Token请求解析失败。")
    else:
        refresh_result = True
    return refresh_result


def refresh_public_app_token() -> bool:
    _logger = logging.getLogger("REF_PUB_TOKEN")
    refresh_result = False
    need_refresh = not redis.exists(config.PUB_ACCESS_TOKEN)
    if not need_refresh:
        expires = pendulum.parse(redis.hget(config.PUB_ACCESS_TOKEN, "expires").decode())
        need_refresh = (expires - pendulum.now()).total_seconds() < 360
    if need_refresh:
        try:
            token_request = requests.get("https://api.weixin.qq.com/cgi-bin/token",
                                         params={
                                             "grant_type": "client_credential",
                                             "appid": config.PUB_APP_ID,
                                             "secret": config.PUB_APP_SECRET
                                         })
            token_request.raise_for_status()
            token_result = token_request.json()
            if "errcode" not in token_result:
                expires = pendulum.now().add(seconds=token_result["expires_in"])
                pipe = redis.pipeline()
                pipe.hset(config.PUB_ACCESS_TOKEN, "token", token_result["access_token"])
                pipe.hset(config.PUB_ACCESS_TOKEN, "expires", expires.to_atom_string())
                pipe.execute()
                _logger.info("刷新公众号Token成功。")
                refresh_result = True
            else:
                _logger.info(f"刷新公众号Token出现错误，"
                             f"错误码{token_result['errcode']}：{token_result['errmsg']}。")
        except requests.ConnectionError:
            _logger.error(f"刷新公众号Token时无法建立与微信服务器的连接。")
        except ValueError:
            _logger.error(f"公众号Access Token请求解析失败。")
    else:
        refresh_result = True
    return refresh_result


def refresh_public_app_js_api_ticket() -> bool:
    _logger = logging.getLogger("REF_PUB_JS_TICKET")
    refresh_result = False
    need_refresh = not redis.exists(config.PUB_JS_API_TOKEN)
    if not need_refresh:
        expires = pendulum.parse(redis.hget(config.PUB_JS_API_TOKEN, "expires").decode())
        need_refresh = (expires - pendulum.now()).total_seconds() < 360
    if need_refresh:
        try:
            token_request = requests.get("https://api.weixin.qq.com/cgi-bin/ticket/getticket",
                                         params={
                                             "access_token": redis.hget(config.PUB_ACCESS_TOKEN, "token"),
                                             "type": "jsapi"
                                         })
            token_result = token_request.json()
            if "errcode" in token_result and token_result["errcode"] == 0:
                expires = pendulum.now().add(seconds=token_result["expires_in"])
                pipe = redis.pipeline()
                pipe.hset(config.PUB_JS_API_TOKEN, "token", token_result["ticket"])
                pipe.hset(config.PUB_JS_API_TOKEN, "expires", expires.to_atom_string())
                pipe.execute()
                _logger.info("刷新服务号应用JSAPI TICKET成功。")
                refresh_result = True
            else:
                _logger.error(f"刷新服务号应用JSAPI TICKET出现错误，"
                              f"错误码{token_result['errcode']}：{token_result['errmsg']}。")
        except requests.ConnectionError:
            _logger.error(f"刷新服务号应用JSAPI TICKET时无法建立与微信服务器的连接。")
        except ValueError:
            _logger.error(f"刷新服务号应用JSAPI TICKET时Access Token请求解析失败。")
    else:
        refresh_result = True
    return refresh_result


def web_tokens_surveillance():
    _logger = logging.getLogger("REF_USER_TOKEN")
    scan_keys = redis.keys("*_web")
    total = len(scan_keys)
    deleted = 0
    refreshed = 0
    try:
        while len(scan_keys) > 0:
            current = scan_keys.pop()
            current_refresh_expires = pendulum.parse(redis.hget(current, "refresh_expires").decode())
            if current_refresh_expires <= pendulum.now():
                redis.delete(current)
                deleted += 1
                continue
            current_token_expires = pendulum.parse(redis.hget(current, "web_expires").decode())
            if current_token_expires <= pendulum.now():
                refresh_request = requests.get("https://api.weixin.qq.com/sns/oauth2/refresh_token",
                                               params={
                                                   "appid": config.PUB_APP_ID,
                                                   "grant_type": "refresh_token",
                                                   "refresh_token": redis.hget(current,
                                                                               config.PUB_WEB_REFRESH_TOKEN
                                                                               ).decode()
                                               })
                refresh_request.raise_for_status()
                refresh_response = refresh_request.json()
                if "errcode" not in refresh_response:
                    pipe = redis.pipeline()
                    pipe.hset(current, config.PUB_WEB_TOKEN, refresh_response["access_token"])
                    expires = pendulum.now().add(seconds=refresh_response["expires_in"])
                    pipe.hset(current, "web_expires", expires.to_atom_string())
                    pipe.execute()
                    refreshed += 1
            time.sleep(10)
        _logger.info(f"共有公众号用户Token {total} 个，超时删除 {deleted} 个，刷新 {refreshed} 个。")
    except requests.ConnectionError:
        _logger.info(f"刷新出现错误。")
